<template>
	<div>
		<transition name="el-fade-in-linear">
			<div :id="refId" class="drag-box" ref="dragBox" v-if="isShow">
				<div
					v-drag="{
						refId,
						isMobile: browser.isMobile
					}"
					ref="dragIcon"
					class="flex flex-justify-center flex-align-center dragIcon"
					:class="{ bounce }"
					@touchstart.stop="onTouchStart"
					@touchmove.prevent.stop="onTouchMove($event)"
					@touchend.stop="onTouchEnd"
					@click="onClick"
					:style="{
						position: browser.isMobile ? 'fixed' : 'absolute',
						left: left + 'px',
						top: top + 'px',
						width: width + 'px',
						height: height + 'px',
						backgroundColor: backgroundColor
					}"
				>
					<slot />
				</div>
			</div>
		</transition>
	</div>
</template>

<script>
import { mapGetters } from "vuex";
import { uuid } from "@/utils";
const { clientWidth, clientHeight } = document.documentElement;
export default {
	name: "cl-float-ball",
	directives: {
		drag(el, bind) {
			const oDiv = el;
			const { refId, isMobile } = bind.value;
			// 拖拽时间标识
			let firstTime = "";
			let lastTime = "";
			document.onselectstart = function() {
				return true;
			};
			oDiv.onmousedown = function(e) {
				if (isMobile) return;
				// 为了区分点击还是拖拽，使用时间差来判断，200毫秒内为点击，200毫秒外为拖拽，初始化为点击
				document.getElementById(refId).setAttribute("drag-flag", false);
				firstTime = new Date().getTime();

				// oDiv.offsetParent.offsetWidth - oDiv.offsetLeft - oDiv.offsetWidth
				// 表示元素距离父元素右边距的距离
				const disX =
					oDiv.offsetParent.offsetWidth - oDiv.offsetLeft - oDiv.offsetWidth + e.clientX;
				// oDiv.offsetTop 表示距离父元素顶边距的距离
				const disY = oDiv.offsetTop - e.clientY;
				// 设置最大右边距
				const maxRight = oDiv.offsetParent.offsetWidth - oDiv.offsetWidth;
				// 设置最大顶边距
				const maxTop = oDiv.offsetParent.offsetHeight - oDiv.offsetHeight;
				document.onmousemove = function(e) {
					// 计算当前右边距并设置
					const r = Math.min(maxRight, Math.max(disX - e.clientX, 0));
					oDiv.style.right = r + "px";
					oDiv.style.left = "auto";
					// 计算当前顶边距并设置
					const t = Math.min(maxTop, Math.max(disY + e.clientY, 0));
					oDiv.style.top = t + "px";

					// 判断下当前时间与初始时间差，大于200毫秒则判断状态为拖拽
					lastTime = new Date().getTime();
					if (lastTime - firstTime > 200) {
						document.getElementById(refId).setAttribute("drag-flag", true);
					}
				};
				// 鼠标抬起时清除事件
				document.onmouseup = function(e) {
					document.onmousemove = null;
					document.onmouseup = null;
				};
				return false;
			};
		}
	},
	props: {
		width: {
			type: Number,
			default: 60
		},
		height: {
			type: Number,
			default: 60
		},
		//视口宽
		clientWidth: {
			type: Number,
			default: clientWidth
		},
		//视口高
		clientHeight: {
			type: Number,
			default: clientHeight
		},
		offsetX: {
			type: Number,
			default: 15
		},
		offsetY: {
			type: Number,
			default: 15
		},
		bounce: {
			type: Boolean,
			default: false
		},
		backgroundColor: {
			type: String,
			default: '#8f44eb'
		},
		borderColor: {
			type: String,
			default: '#7e2de2'
		}
	},
	data() {
		return {
			refId: uuid(),
			left: 0,
			top: 0,
			startToMove: false,
			isShow: true,
			timer: null,
			currentTop: null
		};
	},
	computed: {
		...mapGetters(["browser"])
	},
	created() {
		const { offsetX, offsetY } = this;
		this.left = this.clientWidth - this.width - offsetX;
		this.top = clientHeight - this.height - offsetY;
	},
	mounted() {
		this.bindScrollEvent();
		document.onselectstart = function() {
			return true;
		};
		// 记得销毁一些全局的的事件
		this.$once("hook:beforeDestroy", () => {
			this.removeScrollEvent();
		});
	},
	methods: {
		onClick(e) {
			// 点击事件触发时，判断当前状态是拖拽还是点击，若是拖拽，直接返回不继续执行
			const isDrag = document.getElementById(this.refId).getAttribute("drag-flag");
			if (isDrag == "true") {
				return;
			}
			this.$emit("click", e);
		},
		onTouchStart() {
			this.startToMove = true;
			this.$refs.dragIcon.style.transition = "none";
		},
		onTouchMove(e) {
			const clientX = e.targetTouches[0].clientX; //手指相对视口的x
			const clientY = e.targetTouches[0].clientY; //手指相对视口的y
			const isInScreen =
				clientX <= clientWidth && clientX >= 0 && clientY <= clientHeight && clientY >= 0;
			if (this.startToMove && e.targetTouches.length === 1) {
				if (isInScreen) {
					this.left = clientX - this.width / 2;
					this.top = clientY - this.height / 2;
				}
			}
		},
		onTouchEnd() {
			if (this.left < this.clientWidth / 2) {
				this.left = 15; //不让贴边 所以设置15没设置0
				this.onIconY();
			} else {
				this.left = this.clientWidth - this.width - 15; //不让贴边 所以减15
				this.onIconY();
			}
			this.$refs.dragIcon.style.transition = "all .3s";
		},
		onIconY() {
			if (this.top < 0) {
				this.top = clientHeight - this.clientHeight + 15; //不上帖上边所以设置为15 没设置0
			} else if (this.top + this.height > this.clientHeight) {
				this.top = clientHeight - this.height - 15; //不让帖下边所以减15
			}
		},
		bindScrollEvent() {
			window.addEventListener("scroll", this.onScrollStart);
		},
		removeScrollEvent() {
			window.removeEventListener("scroll", this.onScrollStart);
		},
		onScrollStart() {
			this.isShow = false;
			this.timer && clearTimeout(this.timer);
			this.timer = setTimeout(() => {
				this.onScrollEnd();
			}, 300);
			this.currentTop = document.documentElement.scrollTop || document.body.scrollTop;
		},
		onScrollEnd() {
			this.scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
			// 判断是否停止滚动的条件
			if (this.scrollTop == this.currentTop) {
				this.isShow = true;
			}
		}
	}
};
</script>

<style lang="scss" scoped>
.drag-box {
	z-index: 996;
}
.dragIcon {
	// position: fixed;
	z-index: 2001;
	width: 60px;
	height: 60px;
	border-radius: 50%;
	background-color: #156dff !important;
	border-style: solid;
	border-width: 1px;
	box-sizing: border-box;
	text-align: center;
	color: #fff;
	cursor: pointer;
	&.bounce {
		animation: ani-bounce 1s linear infinite alternate;
	}
}
@keyframes ani-bounce {
	from {
		transform: translateY(0);
	}
	to {
		transform: translateY(-20px);
	}
}
.v-enter {
	opacity: 1;
}
.v-leave-to {
	opacity: 0;
}
.v-enter-active,
.v-leave-active {
	transition: opacity 0.3s;
}
</style>
